package com.example.service.impl;
import java.util.Set;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;



/**
 * 
 * @author qxw
 * 2017年10月24日
 */
@Service
public class RedisTemplateImpl {
	private Logger logger = LoggerFactory.getLogger("RedisTemplateImpl");
	
	@Autowired
    private StringRedisTemplate stringRedisTemplate;
     

	@Autowired
    private RedisTemplate<?, ?> redisTemplate;
	
	public void set(final String key, final String value) {
		redisTemplate.execute(new RedisCallback<Object>() {
			@Override
			public Object doInRedis(RedisConnection connection)
					throws DataAccessException {
				connection.set(
						redisTemplate.getStringSerializer().serialize(key),
						redisTemplate.getStringSerializer().serialize(value));
				logger.debug("save key:" + key + ",value:" + value);
				return null;
			}
		});
	}


	
	public String get(final String key) {
		return redisTemplate.execute(new RedisCallback<String>() {
			@Override
			public String doInRedis(RedisConnection connection)
					throws DataAccessException {
				byte[] byteKye = redisTemplate.getStringSerializer().serialize(
						key);
				if (connection.exists(byteKye)) {
					byte[] byteValue = connection.get(byteKye);
					String value = redisTemplate.getStringSerializer()
							.deserialize(byteValue);
					logger.debug("key:" + key + ",value:" + value);
					return value;
				}
				logger.error("该key不存在值,key:"+key);
				return null;
			}
		});
	}

	public void delete(final String key) {
		redisTemplate.execute(new RedisCallback<Object>() {
			public Object doInRedis(RedisConnection connection) {
				connection.del(redisTemplate.getStringSerializer().serialize(
						key));
				return null;
			}
		});
	}

	
	 /**
     * @param key
     * @return
     */
	public boolean exists(final String key) {
        return 	(boolean) redisTemplate.execute(new RedisCallback<Object>() {
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.exists(key.getBytes());
            }
        });
    }
	
    /**
     * @return
     */
	public String ping() {
        return 	(String) redisTemplate.execute(new RedisCallback<Object>() {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.ping();
            }
        });
    }
	
	
	public void lPush(final String key, final String value){
		redisTemplate.execute(new RedisCallback<Object>() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.lPush(redisTemplate.getStringSerializer().serialize(key),
						redisTemplate.getStringSerializer().serialize(value));
            }
        });
	}
	
	
	public String rpoplpush(final String srcKey, final String dstKey){
		return redisTemplate.execute(new RedisCallback<String>() {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
            	byte[] val = connection.rPopLPush(srcKey.getBytes(), dstKey.getBytes());
                return new String(val);
            }
        });
	}
	
	public String lPop(final String key){
		return redisTemplate.execute(new RedisCallback<String>() {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
            	byte[] val=connection.lPop(key.getBytes());
            	return new String(val);
            }
        });
	}
	
	public String rPop(final String key){
		return redisTemplate.execute(new RedisCallback<String>() {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
            	 connection.rPop(key.getBytes());
                 return "1";
            }
        });
	}
	
	public Integer decr(final String key){
		return redisTemplate.execute(new RedisCallback<Integer>() {
            public Integer doInRedis(RedisConnection connection) throws DataAccessException {
            	Long ll = connection.decr(key.getBytes());
            	return Integer.valueOf(String.valueOf(ll));
            }
        });
	}
	 
	public long incr(final String key) {
        return 	(long) redisTemplate.execute(new RedisCallback<Object>() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.incr(key.getBytes());
            }
        });
    }
	
	
	public long decrby(final String key) {
        return 	(long) redisTemplate.execute(new RedisCallback<Object>() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.decrBy(key.getBytes(), -1);
            }
        });
    }
	
	public String lLen(final String key){
		return redisTemplate.execute(new RedisCallback<String>() {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
        			Long lLen = connection.lLen(key.getBytes());
        			return String.valueOf(lLen);
            }
        });
	}
	
	
	public String sAdd(final String key,final String value){
		return redisTemplate.execute(new RedisCallback<String>() {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
        			Long lLen = connection.sAdd(redisTemplate.getStringSerializer().serialize(key),
        										redisTemplate.getStringSerializer().serialize(value));
        			return String.valueOf(lLen);
            }
        });
	}
	
	
	public StringBuffer sMembers(final String key){
		return redisTemplate.execute(new RedisCallback<StringBuffer>() {
            public StringBuffer doInRedis(RedisConnection connection) throws DataAccessException {
            	Set<byte[]> bytes = connection.sMembers(redisTemplate.getStringSerializer().serialize(key));
            	StringBuffer stringBuffer = new StringBuffer();
            	for (byte[] bs : bytes) {
            		stringBuffer.append(new String(bs) + ",");
				}
            	return stringBuffer;
            }
        });
	}
	
	/**
	 * 判断 member 元素是否集合 key 的成员。
	 * @param key
	 * 返回值:
			如果 member 元素是集合的成员，返回true 。
			如果 member 元素不是集合的成员，或 key 不存在，返回 false 。
	 */
	public Boolean sisMember(final String key,final String member){
		return redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
            	Boolean a = connection.sIsMember(redisTemplate.getStringSerializer().serialize(key),
						redisTemplate.getStringSerializer().serialize(member));
            	return a;
            }
        });
	}
	

	
	/**
	 * 命令在指定的 key 不存在时，为 key 设置指定的值
	 * @param key
	 * @param value
	 * @return
	 * 2017年11月13日
	 */
	public Boolean setNx(final String key,final String value){
		return redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
            	return connection.setNX(redisTemplate.getStringSerializer().serialize(key),redisTemplate.getStringSerializer().serialize(value));
            	
            }
        });
	}
	
	
	
	/**
	 * 设置key的有效期
	 * @param key
	 * @param seconds
	 * 2017年11月13日
	 */
	public void expire(final String key, final Long seconds) {
		redisTemplate.execute(new RedisCallback<Object>() {
			@Override
			public Object doInRedis(RedisConnection connection)
					throws DataAccessException {
				connection.expire(key.getBytes(), seconds);
				logger.debug("save key:" + key + ",value:" + seconds);
				return null;
			}
		});
	}
	
	
	/**
	 * TTL 命令以秒为单位返回 key 的剩余过期时间。
	 * @param key
	 * @return
	 * 2017年11月13日
	 */
	public long ttl(final String key) {
        return 	(long) redisTemplate.execute(new RedisCallback<Object>() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.ttl(key.getBytes());
            }
        });
    }
	 
	public void watch(final String key) {
		redisTemplate.execute(new RedisCallback<Object>() {
			@Override
			public Object doInRedis(RedisConnection connection)
					throws DataAccessException {
				connection.watch(key.getBytes());
				return null;
			}
		});
	}
	
		/**
		 * 加锁
		 * @param locaName   锁的key
		 * @param acquireTimeout  获取超时时间
		 * @param timeout	 锁的超时时间
		 * @return 锁标识
		 * 2017年11月13日
		 */
	  public String lock(String locaName,long acquireTimeout, long timeout){
		  String retIdentifier = null;
		  // 随机生成一个value
          String identifier = UUID.randomUUID().toString();
          // 锁名，即key值
          String lockKey = "lock:" + locaName;
          // 超时时间，上锁后超过此时间则自动释放锁
          long lockExpire =timeout/1000;
          // 获取锁的超时时间，超过这个时间则放弃获取锁
          long end = System.currentTimeMillis() + acquireTimeout;
          //当前时间小于超市时间进入循环体判断
          while(System.currentTimeMillis() < end) {
        	  if (setNx(lockKey, identifier)){
        		  expire(lockKey, lockExpire);
        		  retIdentifier = identifier;
                  return retIdentifier;
        	  }
        	  // 返回-1代表key没有设置超时时间，为key设置一个超时时间
              if (ttl(lockKey) == -1) {
                  expire(lockKey, lockExpire);
              }
              try {
                  Thread.sleep(100);
              } catch (InterruptedException e) {
                  Thread.currentThread().interrupt();
              }
          }
		  return retIdentifier;	    	
	   }
	
	  
	  
	/**
	 * 释放锁
	 * @param lockName 锁的key
	 * @param identifier  释放锁的标识
	 * @return
	 * 2017年11月13日
	 */
	  public boolean releaseLock(String lockName, String identifier) {
		  String lockKey = "lock:" + lockName;
		  boolean retFlag = false;
		  while (true) {
			// 通过前面返回的value值判断是不是该锁，若是该锁，则删除，释放锁
              if (identifier.equals(get(lockKey))) {

            	 	delete(lockKey);

                   retFlag = true;
              }

              break;
		  }
		 return retFlag;
		  
	  }
	  
	  
	  
	  
}
